#pragma once
#include<iostream>
#include <opencv2/opencv.hpp>
#include <chrono>
#include <thread>
#include <deque>
#include<MvCameraControl.h>
#include <../ultralytics-8.3.168/try.cpp>

class Image_Loading {

private:
    std::deque<std::chrono::time_point<std::chrono::high_resolution_clock>> frameTimes;
    const int frameTimeBufferSize = 10; // 用于计算FPS的帧数

public:
    // 海康相机API
    void import_image(){
        int nRet = MV_OK;
        void* handle = NULL;

        // 1. 枚举设备
        MV_CC_DEVICE_INFO_LIST stDeviceList;
        memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
        nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
        if (nRet != MV_OK || stDeviceList.nDeviceNum == 0) {
            printf("No camera found or enum failed! nRet = 0x%x\n", nRet);
            return;
        }

        // 2. 选择设备并创建句柄
        unsigned int nIndex = 0;
        printf("Please input camera index (0~%d): ", stDeviceList.nDeviceNum - 1);
        scanf("%d", &nIndex);
        if (nIndex >= stDeviceList.nDeviceNum) {
            printf("Input error!\n");
            return;
        }
        nRet = MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[nIndex]);
        if (nRet != MV_OK) {
            printf("Create handle failed! nRet = 0x%x\n", nRet);
            return;
        }

        // 3. 打开设备
        nRet = MV_CC_OpenDevice(handle);
        if (nRet != MV_OK) {
            printf("Open device failed! nRet = 0x%x\n", nRet);
            MV_CC_DestroyHandle(handle);
            return;
        }

        // 设置相机参数
        setupCamera(handle);

        // 4. 设置触发模式为off（连续采集）
        nRet = MV_CC_SetEnumValue(handle, "TriggerMode", 0);
        if (nRet != MV_OK) {
            printf("Set TriggerMode failed! nRet = 0x%x\n", nRet);
        }

        // 5. 开始取流
        nRet = MV_CC_StartGrabbing(handle);
        if (nRet != MV_OK) {
            printf("Start grabbing failed! nRet = 0x%x\n", nRet);
            MV_CC_CloseDevice(handle);
            MV_CC_DestroyHandle(handle);
            return;
        }

        // 6. 获取一帧图像
        MV_FRAME_OUT_INFO_EX stImageInfo = {0};
        unsigned char* pData = (unsigned char*)malloc(1920*1080*3); // 预分配空间
        unsigned char* pDstBuf = nullptr; 
        
        while (true) {
            // 记录当前时间用于FPS计算
            auto currentTime = std::chrono::high_resolution_clock::now();
            frameTimes.push_back(currentTime);
            
            // 保持缓冲区大小固定
            if (frameTimes.size() > frameTimeBufferSize) {
                frameTimes.pop_front();
            }

            nRet = MV_CC_GetOneFrameTimeout(handle, pData, 1920*1080*3, &stImageInfo, 1000); // 这个代码是什么意思？
            if (nRet == MV_OK) { // 这里很容易崩 也就是为false,很不稳定的原因是什么？
                cv::Mat img;
                static bool isInit = false;
                if (stImageInfo.enPixelType == PixelType_Gvsp_Mono8) {
                    img = cv::Mat(stImageInfo.nHeight, stImageInfo.nWidth, CV_8UC1, pData);
                } else if (stImageInfo.enPixelType == PixelType_Gvsp_RGB8_Packed) {
                    img = cv::Mat(stImageInfo.nHeight, stImageInfo.nWidth, CV_8UC3, pData);
                    cv::cvtColor(img, img, cv::COLOR_RGB2BGR);
                } else if (stImageInfo.enPixelType == PixelType_Gvsp_BayerRG8) {
                    // 只在第一次需要时分配内存，避免重复分配释放
                    if (!isInit) {
                        pDstBuf = (unsigned char*)malloc(stImageInfo.nWidth * stImageInfo.nHeight * 3);
                        isInit = true;
                    }
                    
                    MV_CC_PIXEL_CONVERT_PARAM stConvertParam = {0};
                    stConvertParam.nWidth = stImageInfo.nWidth;
                    stConvertParam.nHeight = stImageInfo.nHeight;
                    stConvertParam.pSrcData = pData;
                    stConvertParam.nSrcDataLen = stImageInfo.nFrameLen;
                    stConvertParam.enSrcPixelType = stImageInfo.enPixelType;
                    // 核心优化：直接让SDK输出BGR格式，省去手动交换步骤
                    stConvertParam.enDstPixelType = PixelType_Gvsp_BGR8_Packed;  // 目标格式改为BGR
                    stConvertParam.pDstBuffer = pDstBuf;
                    stConvertParam.nDstBufferSize = stImageInfo.nWidth * stImageInfo.nHeight * 3;

                    int nRetConvert = MV_CC_ConvertPixelType(handle, &stConvertParam);
                    if (nRetConvert == MV_OK) {
                        // 直接使用BGR格式图像，无需再调用cvtColor
                        cv::Mat img(stImageInfo.nHeight, stImageInfo.nWidth, CV_8UC3, pDstBuf);
                        // 程序调用处理每一帧
                        //yolo工具包


                    
                        // 计算并显示FPS
                        float fps = calculateFPS();
                        displayFPS(img, fps);
                        

                        imshow("Camera Image", img);

                    } else {
                        printf("像素格式转换失败! nRet = 0x%x\n", nRetConvert);
                    }
                } else {
                    printf("Unsupported pixel format! PixelType: 0x%lx\n", stImageInfo.enPixelType);
                }
                

            } else {
                printf("Get frame failed! nRet = 0x%x\n", nRet);
                break;
            }        
            if (cv::waitKey(1) == 27) break; // 按ESC退出
        }
        
        free(pData);
        // 在这里释放pDstBuf（循环外）
        if (pDstBuf) {
            free(pDstBuf);
            pDstBuf = nullptr;
        }        
        // 8. 停止取流，关闭设备，销毁句柄
        MV_CC_StopGrabbing(handle);
        MV_CC_CloseDevice(handle);
        MV_CC_DestroyHandle(handle);
    }

    float calculateFPS();

    void displayFPS(cv::Mat& image, float fps);

    void setupCamera(void * handle);
};


// 计算帧率
float Image_Loading::calculateFPS() {
    if (frameTimes.size() < 2) {
        return 0.0f;
    }
    
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
        frameTimes.back() - frameTimes.front()
    ).count();
    
    if (duration <= 0) {
        return 0.0f;
    }
    
    return (frameTimes.size() - 1) * 1000.0f / duration;
}

// 在图像上显示帧率
void Image_Loading::displayFPS(cv::Mat& image, float fps) {
    std::stringstream ss;
    ss << "FPS: " << std::fixed << std::setprecision(1) << fps;
        
    cv::putText(
        image, 
        ss.str(), 
        cv::Point(10, 30),  // 左上角位置
        cv::FONT_HERSHEY_SIMPLEX, 
        0.7,                // 字体大小
        cv::Scalar(0, 255, 0),  // 绿色
        2,                  // 线宽
        cv::LINE_AA         // 抗锯齿
    );
}

// 摄像头参数
void Image_Loading::setupCamera(void *handle){
    int nRet = MV_OK;

    // 关闭自动曝光模式
    nRet = MV_CC_SetEnumValue(handle, "ExposureAuto", 0); // 0表示手动模式
    // nRet = MV_CC_SetEnumValue(handle, "GammaAuto", 0); // 0=手动模式，1=自动模式
    nRet = MV_CC_SetFloatValue(handle, "GainAuto", 0);
    // 参数调节
    float targetExposure = 5000;  // 目标曝光时间
    // float targetGamma = 1.5f; // 设置伽马值为1.5（增强暗部细节）
    float targetGain = 8.0f; // 你需要的增益值（单位通常为dB，具体范围查相机手册）
    
    

    nRet = MV_CC_SetFloatValue(handle, "ExposureTime", targetExposure);
    if (nRet != MV_OK) {
        printf("Set ExposureTime failed! nRet = 0x%x\n", nRet);
    }

    nRet = MV_CC_SetFloatValue(handle, "Gain", targetGain);
    if (nRet != MV_OK) {
        printf("Set Gain failed! nRet = 0x%x\n", nRet);
    }

    // nRet = MV_CC_SetFloatValue(handle, "Gamma", targetGamma);
    // if (nRet != MV_OK) {
    //     printf("Set Gamma failed! nRet = 0x%x\n", nRet);
    // }
}
